﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using FlanProjectData.Skills;
using System.Text;

namespace FlanProjectData.Managers
{
    public class SequenceManager : InputManager
    {
        public static TimeSpan LastInputTime { get; set; }
        public static List<Action> Buffer { get; set; }

        public static readonly TimeSpan BufferTimeOut = TimeSpan.FromMilliseconds(500);
        public static readonly TimeSpan MergeInputTime = TimeSpan.FromMilliseconds(100);

        #region Combat Action List

        internal static readonly List<Action> Directions = new List<Action>()
        {
            Action.MoveUp,
            Action.MoveDown,
            Action.MoveLeft,
            Action.MoveRight
        };

        internal static readonly List<Action> NonDirections = new List<Action>()
        {
            Action.Attack,
            Action.Defend,
            Action.Skill
        };

        #endregion

        // Overloaded from InputManager
        public static new void Initialize()
        {
            ResetActionMaps();
            Buffer = new List<Action>((int)Action.TotalActionCount);
        }

        public static Action FromInput()
        {
            var direction = Action.None;

            if (IsActionPressed(Action.MoveUp))
            {
                direction |= Action.MoveUp;
            }
            else if (IsActionPressed(Action.MoveDown))
            {
                direction |= Action.MoveDown;
            }

            if (IsActionPressed(Action.MoveLeft))
            {
                direction |= Action.MoveLeft;
            }
            else if (IsActionPressed(Action.MoveRight))
            {
                direction |= Action.MoveRight;
            }

            return direction;
        }

        public static Action FromPreviousInput()
        {
            var direction = Action.None;

            if (IsPreviousActionPressed(Action.MoveUp))
            {
                direction |= Action.MoveUp;
            }
            else if (IsPreviousActionPressed(Action.MoveDown))
            {
                direction |= Action.MoveDown;
            }

            if (IsPreviousActionPressed(Action.MoveLeft))
            {
                direction |= Action.MoveLeft;
            }
            else if (IsPreviousActionPressed(Action.MoveRight))
            {
                direction |= Action.MoveRight;
            }

            return direction;
        }

        public static void Update(GameTime gameTime)
        {
            // PreviousKeyboardState = CurrentKeyboardState;
            // CurrentKeyboardState = Keyboard.GetState();

            var time = gameTime.TotalGameTime;
            var timeSinceLast = time - LastInputTime;

            if (timeSinceLast > BufferTimeOut)
            {
                Buffer.Clear();
            }

            var action = Action.None;

            foreach (var key in NonDirections)
            {
                if (IsActionPressed(key))
                {
                    action |= key;
                }
            }

            var mergeInput = (Buffer.Count > 0 && timeSinceLast < MergeInputTime);
            var direction = FromInput();

            if (FromPreviousInput() != direction)
            {
                action |= direction;
                mergeInput = false;
            }

            // Add action to the buffer
            if (action != 0)
            {
                if (mergeInput)
                {
                    Buffer[Buffer.Count - 1] = Buffer[Buffer.Count - 1] | action;
                }
                else
                {
                    if (Buffer.Count == Buffer.Capacity)
                    {
                        Buffer.RemoveAt(0);
                    }

                    Buffer.Add(action);

                    LastInputTime = time;
                }
            }
        }

        public static bool Matches(Skill move)
        {
            var input = String.Empty;

            foreach (var button in Buffer)
            {
                input += button + " ";
            }

            // If the move is longer than the buffer, it can't possibly match.
            if (Buffer.Count < move.Sequence.Length)
            {
                return false;
            }

            // Loop backwards to match against the most recent input.
            for (int i = 1; i <= move.Sequence.Length; ++i)
            {
                if (Buffer[Buffer.Count - i] != move.Sequence[move.Sequence.Length - i])
                {
                    return false;
                }
            }

            // Unless this move is a component of a larger sequence,
            if (!move.IsCancellable)
            {
                // consume the used inputs.
                Buffer.Clear();
            }

            return true;
        }
    }
}
